<

基本的な Flutter レイアウトの概念

Flutter レイアウト コードラボへようこそ。 ここでは、Flutter UI を構築する方法を学びます。 Flutter または Dart をダウンロードしてインストールしてください!

Flutter が他のフレームワークと異なるのは、その UI です。 は、(たとえば) XML ファイルなどではなく、コードに組み込まれます。 ウィジェットは、Flutter UI の基本的な構成要素です。 このコードラボを進めていくと、 Flutter のほとんどすべてがウィジェットであることがわかります。 ウィジェットは、UI の特定の部分を記述する不変オブジェクトです。 また、Flutter ウィジェットは構成可能であることも学びます。 既存のウィジェットを組み合わせて、より洗練されたウィジェットを作成できるということです。 この終わりにコードラボ、 学んだことを応用できるようになります 名刺を表示する Flutter UI の構築に取り組みます。

このコードラボを完了するのにかかる推定時間: 45 ~ 60 分。

行クラスと列クラス

RowColumnウィジェットを含み、レイアウトするクラスです。 内のウィジェットRowまたColumn呼ばれます子供、 とRowColumnと呼ばれます両親Rowウィジェットを水平にレイアウトします。 とColumnウィジェットを垂直にレイアウトします。

例: 列の作成

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        BlueBox(),
        BlueBox(),
        BlueBox(),
      ],
    );
  }
}

class BlueBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        color: Colors.blue,
        border: Border.all(),
      ),
    );
  }
}
{$ end main.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        color: const Color(0xffeeeeee),
        child: Center(
          child: Container(
            color: const Color(0xffcccccc),
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;
  
  runApp(MyApp());

  final controller = LiveWidgetController(WidgetsBinding.instance);

  final columns = controller.widgetList(find.byType(Column));

  if (columns.isEmpty) {
    _result(false, ['The Row contains three BlueBox widgets and lays them out horizontally.']);
    return;
  }

  if (columns.length > 1) {
    _result(false, ['Found ${columns.length} Rows, rather than just one.']);
    return;
  }

  final column = columns.first as Column;

  if (column.children.length != 3 || column.children.any((w) => w is! BlueBox)) {
    _result(false, ['Row/Column should contain three children, all BlueBox widgets.']);
    return;
  }

  _result(true, ['The Column contains three BlueBox widgets and lays them out vertically.']);
}
{$ end test.dart $}

軸のサイズと配置

これまでのところ、BlueBoxウィジェットがまとめられています (UI 出力の左側または上部)。 方法を変更できます。BlueBoxウィジェットは間隔をあけて配置されます 軸のサイズと位置合わせのプロパティを使用して出力します。

mainAxisSize プロパティ

RowColumn異なる主軸を占めます。 あRowの主軸は水平であり、 そしてColumnの主軸は垂直です。 のmainAxisSize財産がいくらかを決める スペースRowColumn主軸を占めることができます。 のmainAxisSizeプロパティには次の 2 つの値があります。

MainAxisSize.max
RowColumn主軸上のすべてのスペースを占有します。 子の幅を合わせた場合、 主軸上の合計スペースよりも小さい、 彼らの子供たちは余分なスペースをとって配置されています。
MainAxisSize.min
RowColumn主軸上の十分なスペースのみを占有します 彼らの子供たちのために。彼らの子供たちは余分なスペースなしで配置されています そして主軸の真ん中にあります。

例: 軸サイズの変更

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.max,
      children: [
        BlueBox(),
        BlueBox(),
        BlueBox(),
      ],
    );
  }
}

class BlueBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        color: Colors.blue,
        border: Border.all(),
      ),
    );
  }
}
{$ end main.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        color: const Color(0xffeeeeee),
        child: Center(
          child: Container(
            color: const Color(0xffcccccc),
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();

  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });

  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  final rows = controller.widgetList(find.byType(Row));

  if (rows.isEmpty) {
    _result(false, ['Couldn\'t find Row!']);
    return;
  }

  if (rows.length > 1) {
    _result(false, ['Found ${rows.length} Rows, rather than just one.']);
    return;
  }

  final row = rows.first as Row;

  if (row.mainAxisSize != MainAxisSize.min) {
    _result(false, ['Row lays out the BlueBox widgets with extra space. Change MainAxisSize.max to MainAxisSize.min']);
    return;
  }

  if (row.children.length != 3 || row.children.any((w) => w is! BlueBox)) {
    _result(false, ['There should only be three children, all BlueBox widgets.']);
    return;
  }

  _result(true, ['Row lays out the BlueBox widgets without extra space, and the BlueBox widgets are positioned at the middle of Row\'s main axis.']);
}
{$ end test.dart $}

mainAxisAlignment プロパティ

いつmainAxisSizeに設定されていますMainAxisSize.maxRowColumn子どもたちに余分なスペースを与えてレイアウトするかもしれません。 のmainAxisAlignmentプロパティは方法を決定しますRowColumnその余分なスペースに子供たちを配置できます。mainAxisAlignment可能な値は次の 6 つです。

MainAxisAlignment.start
子を主軸の先頭近くに配置します。 (出発したRow、トップのColumn)
MainAxisAlignment.end
子を主軸の端近くに配置します。 (右のRow、下側Column)
MainAxisAlignment.center
子を主軸の中央に配置します。
MainAxisAlignment.spaceBetween
余分なスペースを子間で均等に分割します。
MainAxisAlignment.spaceEvenly
余分なスペースを子供たちに均等に分割します そして子供たちの前と後。
MainAxisAlignment.spaceAround
に似ているMainAxisAlignment.spaceEvenly、 ただし、最初のスペースの前のスペースの半分が減ります 子と最後の子以降 子間の幅の半分まで。

例: 主軸の位置合わせを変更する

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.start,
      children: [
        BlueBox(),
        BlueBox(),
        BlueBox(),
      ],
    );
  }
}

class BlueBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        color: Colors.blue,
        border: Border.all(),
      ),
    );
  }
}
{$ end main.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        color: const Color(0xffeeeeee),
        child: Center(
          child: Container(
            color: const Color(0xffcccccc),
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();

  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });

  await completer.future;
  final controller = LiveWidgetController(WidgetsBinding.instance);

  final rows = controller.widgetList(find.byType(Row));

  if (rows.isEmpty) {
    _result(false, ['Couldn\'t find a Row!']);
    return;
  }

  if (rows.length > 1) {
    _result(false, ['Found ${rows.length} Rows, rather than just one.']);
    return;
  }

  final row = rows.first as Row;

  if (row.mainAxisSize != MainAxisSize.max) {
    _result(false, ['It\'s best to leave the mainAxisSize set to MainAxisSize.max, so there\'s space for the alignments to take effect.']);
    return;
  }

  if (row.children.length != 3 || row.children.any((w) => w is! BlueBox)) {
    _result(false, ['The Row should have three children, all BlueBox widgets.']);
    return;
  }

  if (row.mainAxisAlignment == MainAxisAlignment.start) {
    _result(false, ['MainAxisAlignment.start positions the BlueBox widgets on the left of the main axis. Change the value to MainAxisAlignment.end.']);
  } else if (row.mainAxisAlignment == MainAxisAlignment.end) {
    _result(true, ['MainAxisAlignment.end positions the BlueBox widgets on the right of the main axis.']);
  } else if (row.mainAxisAlignment == MainAxisAlignment.center) {
    _result(true, ['MainAxisAlignment.center positions the BlueBox widgets at the middle of the main axis.']);
  } else if (row.mainAxisAlignment == MainAxisAlignment.spaceBetween) {
    _result(true, ['The extra space is divided between the BlueBox widgets.']);
  } else if (row.mainAxisAlignment == MainAxisAlignment.spaceEvenly) {
    _result(true, ['The extra space is divided evenly between the BlueBox widgets and before and after them.']);
  } else if (row.mainAxisAlignment == MainAxisAlignment.spaceAround) {
    _result(true, ['Similar to MainAxisAlignment.spaceEvenly, but reduces half of the space before the first BlueBox widget and after the last BlueBox widget to half of the width between the BlueBox widgets.']);
  }
}
{$ end test.dart $}

CrossAxisAlignment プロパティ

crossAxisAlignmentプロパティが決定する どうやってRowColumn子どもたちの位置を決めることができる それらの交差軸上にあります。 あRowの交差軸は垂直であり、 そしてColumnの交差軸は水平です。 のcrossAxisAlignmentプロパティには 5 つの可能な値があります。

CrossAxisAlignment.start
子を交差軸の開始点近くに配置します。 (トップRow、 出発したColumn)
CrossAxisAlignment.end
子を交差軸の端近くに配置します。 (下側はRow、に適していますColumn)
CrossAxisAlignment.center
子を交差軸の中央に配置します。 (真ん中のRow、センターColumn)
CrossAxisAlignment.stretch
交差軸を横切って子を引き伸ばします。 (上から下へRow、左から右へColumn)
CrossAxisAlignment.baseline
キャラクターのベースラインに基づいて子を配置します。 (Textクラスのみであり、textBaselineプロパティはに設定されていますTextBaseline.alphabetic。を参照してください。テキストウィジェット例についてはセクションを参照してください。)

例: 交差軸の位置合わせの変更

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        BlueBox(),
        BiggerBlueBox(),
        BlueBox(),
      ],
    );
  }
}

class BlueBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        color: Colors.blue,
        border: Border.all(),
      ),
    );
  }
}

class BiggerBlueBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 100,
      decoration: BoxDecoration(
        color: Colors.blue,
        border: Border.all(),
      ),
    );
  }
}
{$ end main.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        color: const Color(0xffeeeeee),
        child: Center(
          child: Container(
            color: const Color(0xffcccccc),
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  final rows = controller.widgetList(find.byType(Row));

  if (rows.isEmpty) {
    _result(false, ['Couldn\'t find a Row!']);
    return;
  }

  if (rows.length > 1) {
    _result(false, ['Found ${rows.length} Rows, rather than just one.']);
    return;
  }

  final row = rows.first as Row;

  if (row.children.length != 3 || row.children.any((w) => w is! BlueBox && w is! BiggerBlueBox)) {
    _result(false, ['The Row should have three children, all BlueBox or BiggerBlueBox widgets.']);
    return;
  }

  if (row.crossAxisAlignment == CrossAxisAlignment.start) {
    _result(true, ['The BlueBox and BiggerBlueBox widgets are positioned at the top of the cross axis.']);
  } else if (row.crossAxisAlignment == CrossAxisAlignment.end) {
    _result(true, ['The BlueBox and BiggerBlueBox widgets are positioned at the bottom of the cross axis']);
  } else if (row.crossAxisAlignment == CrossAxisAlignment.center) {
    _result(false, ['The widgets are positioned at the middle of the cross axis. Change CrossAxisAlignment.center to CrossAxisAlignment.start.']);
  } else if (row.crossAxisAlignment == CrossAxisAlignment.stretch) {
    _result(true, ['The BlueBox and BiggerBlueBox widgets are stretched across the cross axis. Change the Row to a Column, and run again.']);
  } else if(row.crossAxisAlignment == CrossAxisAlignment.baseline) {
    _result(false, ['Couldn\t find a text class.']);
  }
}
{$ end test.dart $}

柔軟なウィジェット

ご覧のとおり、mainAxisAlignmentcrossAxisAlignmentプロパティが決定する どうやってRowColumnウィジェットを両方の軸に沿って配置します。RowColumnまず固定サイズのウィジェットをレイアウトします。 固定サイズのウィジェットが考慮されます柔軟性のないなぜなら レイアウト後にサイズを変更することはできません。

Flexibleウィジェットはウィジェットをラップし、 これにより、ウィジェットのサイズが変更可能になります。 ときFlexibleウィジェットはウィジェットをラップし、 ウィジェットはFlexibleウィジェットの子 そして考えられていますフレキシブル。 柔軟性のないウィジェットを配置した後、 ウィジェットはそれに応じてサイズ変更されますflexfitプロパティ。:

flex
自分自身を他と比較するflexの割合を決定する前に、プロパティを確認してください。 それぞれの合計残り容量Flexibleウィジェットが受信します。
fit
かどうかを決定します。Flexibleウィジェット 余分なスペースをすべて埋めます。

例: フィットプロパティの変更

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        BlueBox(),
        Flexible(
          fit: FlexFit.loose,
          flex: 1,
          child: BlueBox(),
        ),
        Flexible(
          fit: FlexFit.loose,
          flex: 1,
          child: BlueBox(),
        ),
      ],
    );
  }
}

class BlueBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        color: Colors.blue,
        border: Border.all(),
      ),
    );
  }
}
{$ end main.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        color: const Color(0xffeeeeee),
        child: Center(
          child: Container(
            color: const Color(0xffcccccc),
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  final rows = controller.widgetList(find.byType(Row));

  if (rows.isEmpty) {
    _result(false, ['Couldn\'t find a Row!']);
    return;
  }

  if (rows.length > 1) {
    _result(false, ['Found ${rows.length} Rows, rather than just one.']);
    return;
  }

  final row = rows.first as Row;

  if (row.mainAxisSize != MainAxisSize.max) {
    _result(false, ['It\'s best to leave the mainAxisSize set to MainAxisSize.max, so there\'s space for the alignments to take effect.']);
    return;
  }
  
  if (row.children.length != 3) {
    _result(false, ['The Row should have three children, all BlueBox or Flexible widgets.']);
    return;
  }

  if (row.children[0] is! BlueBox) {
    _result(false, ['Row\'s first child should be a BlueBox.']);
    return;
  }

  if (row.children[1] is! Flexible) {
    _result(false, ['Row\'s second child should be a Flexible class.']);
    return;
  }

  if (row.children[2] is! Flexible) {
    _result(false, ['Row\'s third child should be a Flexible class.']);
    return;
  }

  final flexibleWidget = row.children[2] as Flexible;
  
  if (flexibleWidget.child is! BlueBox) {
    _result(false, ['The Flexible classes should have BlueBox widgets as their children.']);
    return;
  }

  if (flexibleWidget.fit != FlexFit.tight) {
    _result(false, ['The fit properties set the Flexible widgets to their preferred size. Change both fit values to FlexFit.tight.']);
    return;
  }

  _result(true, ['The Flexible widgets now occupy the space determined by their flex values.']);
}
{$ end test.dart $}

例: フレックス値のテスト

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        BlueBox(),
        Flexible(
          fit: FlexFit.tight,
          flex: 1,
          child: BlueBox(),
        ),
        Flexible(
          fit: FlexFit.tight,
          flex: 1,
          child: BlueBox(),
        ),
      ],
    );
  }
}

class BlueBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        color: Colors.blue,
        border: Border.all(),
      ),
    );
  }
}
{$ end main.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        color: const Color(0xffeeeeee),
        child: Center(
          child: Container(
            color: const Color(0xffcccccc),
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  final rows = controller.widgetList(find.byType(Row));

  if (rows.isEmpty) {
    _result(false, ['Couldn\'t find a Row!']);
    return;
  }

  if (rows.length > 1) {
    _result(false, ['Found ${rows.length} Rows, rather than just one.']);
    return;
  }

  final row = rows.first as Row;

  if (row.children.length != 3) {
    _result(false, ['The Row should have three children, all BlueBlox or Flexible widgets.']);
    return;
  }

  if (row.children[0] is! BlueBox) {
    _result(false, ['The Row\'s first child should be a BlueBox widget.']);
    return;
  }

  if (row.children[1] is! Flexible) {
    _result(false, ['The Row\'s second child should be a Flexible widget.']);
    return;
  }

  if (row.children[2] is! Flexible) {
    _result(false, ['The Row\'s third child should be a Flexible widget.']);
    return;
  }

  final flexibleWidget = row.children[1] as Flexible;
  
  if (flexibleWidget.child is! BlueBox) {
    _result(false, ['The Flexible should have a BlueBox widget as its child.']);
    return;
  }

  if (flexibleWidget.flex != 1) {
    _result(false, ['Notice how the flex properties divide the extra space between the two Flexible widgets.']);
    return;
  }

  _result(true, ['Both Flexible widgets receive half of the total remaining space.']);
}
{$ end test.dart $}

展開されたウィジェット

に似ているFlexibleExpandedウィジェットができます ウィジェットをラップし、ウィジェットが余分なスペースを埋めるように強制します。

例: 余分なスペースを埋める

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        BlueBox(),
        BlueBox(),
        BlueBox(),
      ],
    );
  }
}

class BlueBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        color: Colors.blue,
        border: Border.all(),
      ),
    );
  }
}
{$ end main.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        color: const Color(0xffeeeeee),
        child: Center(
          child: Container(
            color: const Color(0xffcccccc),
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  final rows = controller.widgetList(find.byType(Row));

  if (rows.isEmpty) {
    _result(false, ['Couldn\'t find a Row!']);
    return;
  }

  if (rows.length > 1) {
    _result(false, ['Found ${rows.length} Rows, rather than just one.']);
    return;
  }

  final row = rows.first as Row;
  
  if (row.children.length != 3) {
    _result(false, ['The Row should have three children, all BlueBox widgets.']);
    return;
  }

   if (row.children[0] is! BlueBox) {
    _result(false, ['The Row\'s first child should be a BlueBox widget.']);
    return;
  }

  if (row.children[1] is! Expanded) {
    _result(false, ['Notice how Row contains extra space on its main axis. Wrap the second BlueBox widget in an Expanded widget.']);
    return;
  }

  if (row.children[2] is! BlueBox) {
    _result(false, ['The Row\'s third child should be a Flexible widget.']);
    return;
  }
  
  _result(true, ['Expanded forces second BlueBox widget to fill the extra space.']);
}
{$ end test.dart $}

SizedBox ウィジェット

SizedBoxウィジェットは次の 2 つの方法のいずれかで使用できます。 正確な寸法を作成します。 いつSizedBoxウィジェットをラップすると、ウィジェットのサイズが変更されます を使用してheightwidthプロパティ。 ウィジェットをラップしない場合は、 それはheightwidthプロパティを 空きスペースを作成します。

例: ウィジェットのサイズ変更

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.max,
      children: [
        BlueBox(),
        SizedBox(
          width: 100,
          child: BlueBox(),
        ),
        BlueBox(),
      ],
    );
  }
}

class BlueBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        color: Colors.blue,
        border: Border.all(),
      ),
    );
  }
}
{$ end main.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        color: const Color(0xffeeeeee),
        child: Center(
          child: Container(
            color: const Color(0xffcccccc),
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  final rows = controller.widgetList(find.byType(Row));

  if (rows.isEmpty) {
    _result(false, ['Couldn\'t find a Row!']);
    return;
  }

  if (rows.length > 1) {
    _result(false, ['Found ${rows.length} Rows, rather than just one.']);
    return;
  }

  final row = rows.first as Row;

  if (row.mainAxisSize != MainAxisSize.max) {
    _result(false, ['It\'s best to leave the mainAxisSize set to MainAxisSize.max, so there\'s space for the alignments to take effect.']);
    return;
  }
  
  
  if (row.children.length != 3) {
    _result(false, ['The Row should end up with three children.']);
    return;
  }

  if (row.children[0] is! BlueBox) {
    _result(false, ['The Row\'s first child should be a BlueBox widget.']);
    return;
  }

  if (row.children[1] is! SizedBox) {
    _result(false, ['The Row\'s second child should be a SizedBox widget.']);
    return;
  }

  if (row.children[2] is! BlueBox) {
    _result(false, ['The Row\'s third child should be a BlueBox widget.']);
    return;
  }

  final sizedBox = row.children[1] as SizedBox;
  
  if (sizedBox.width != 100) {
    _result(false, ['The SizedBox should have a width of 100.']);
    return;
  }
  
  if (sizedBox.height != 100) {
    _result(false, ['The SizedBox widget resizes the BlueBox widget to 100 logical pixels wide. Add a height property inside SizedBox equal to 100 logical pixels.']);
    return;
  }
  
  _result(true, ['The SizedBox widget resizes the BlueBox widget to 100 logical pixels wide and tall.']);
}
{$ end test.dart $}

例:スペースの作成

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        BlueBox(),
        const SizedBox(width: 50),
        BlueBox(),
        BlueBox(),
      ],
    );
  }
}

class BlueBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        color: Colors.blue,
        border: Border.all(),
      ),
    );
  }
}
{$ end main.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        color: const Color(0xffeeeeee),
        child: Center(
          child: Container(
            color: const Color(0xffcccccc),
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  final rows = controller.widgetList(find.byType(Row));

  if (rows.isEmpty) {
    _result(false, ['Couldn\'t find a Row!']);
    return;
  }

  if (rows.length > 1) {
    _result(false, ['Found ${rows.length} Rows, rather than just one.']);
    return;
  }

  final row = rows.first as Row;

  if (row.mainAxisSize != MainAxisSize.max) {
    _result(false, ['It\'s best to leave the mainAxisSize set to MainAxisSize.max, so there\'s space for the alignments to take effect.']);
    return;
  }
  
  if (row.mainAxisAlignment == MainAxisAlignment.spaceAround 
      || row.mainAxisAlignment == MainAxisAlignment.spaceBetween 
      || row.mainAxisAlignment == MainAxisAlignment.spaceEvenly) {
    _result(false, ['It\'s best to use MainAxisAlignment.start, MainAxisAlignment.end, or MainAxisAlignment.center to see how the SizedBox widgets work in a Row.']);
    return;
  }
  
  if (row.children.length != 5) {
    _result(false, ['The SizedBox widget creates space at 50 logical pixels wide. Add another SizedBox class between the second and third BlueBox widgets with a width property equal to 25 logical pixels.']);
    return;
  }

  if (row.children[0] is! BlueBox) {
    _result(false, ['The Row\'s first child should be a BlueBox widget.']);
    return;
  }

  if (row.children[1] is! SizedBox) {
    _result(false, ['The Row\'s second child should be a SizedBox widget.']);
    return;
  }

  if (row.children[2] is! BlueBox) {
    _result(false, ['The Row\'s third child should be a BlueBox widget.']);
    return;
  }

  if (row.children[3] is! SizedBox) {
    _result(false, ['The Row\'s fourth child should be a SizedBox widget.']);
    return;  
  }
  
   if (row.children[4] is! BlueBox) {
    _result(false, ['The Row\'s fifth child should be a BlueBox widget.']);
    return;
  }
  
  final sizedBox = row.children[1] as SizedBox;
  
  if (sizedBox.width != 50) {
    _result(false, ['The SizedBox should have a width of 50.']);
    return;
  }
  
  final sizedBox2 = row.children[3] as SizedBox;
  
  if (sizedBox2.width != 25) {
    _result(false, ['SizedBox should have a width of 25.']);
    return;
  }
  
  _result(true, ['The SizedBox widgets create space between the BlueBox widgets, one space at 50 logical pixels and one at 25 logical pixels.']);
}
{$ end test.dart $}

スペーサーウィジェット

に似ているSizedBoxSpacerウィジェットも ウィジェットの間にスペースを作成できます。

例: より多くのスペースを作成する

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        BlueBox(),
        const Spacer(flex: 1),
        BlueBox(),
        BlueBox(),
      ],
    );
  }
}

class BlueBox extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        color: Colors.blue,
        border: Border.all(),
      ),
    );
  }
}
{$ end main.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        color: const Color(0xffeeeeee),
        child: Center(
          child: Container(
            color: const Color(0xffcccccc),
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  final rows = controller.widgetList(find.byType(Row));

  if (rows.isEmpty) {
    _result(false, ['Couldn\'t find a Row!']);
    return;
  }

  if (rows.length > 1) {
    _result(false, ['Found ${rows.length} Rows, rather than just one.']);
    return;
  }

  final row = rows.first as Row;

  if (row.mainAxisSize != MainAxisSize.max) {
    _result(false, ['It\'s best to leave the mainAxisSize set to MainAxisSize.max, so there\'s space for the alignments to take effect.']);
    return;
  }
  
  if (row.mainAxisAlignment == MainAxisAlignment.spaceAround 
      || row.mainAxisAlignment == MainAxisAlignment.spaceBetween 
      || row.mainAxisAlignment == MainAxisAlignment.spaceEvenly) {
    _result(false, ['It\'s best to use MainAxisAlignment.start, MainAxisAlignment.end, or MainAxisAlignment.center to see how the SizedBox widgets work in a Row.']);
    return;
  }
  
  if (row.children.length != 5) {
    _result(false, ['What do you think would happen if you added another Spacer widget with a flex value of 1 between the second and third BlueBox widgets?']);
    return;
  }

  if (row.children[0] is! BlueBox ||
     row.children[1] is! Spacer ||
     row.children[2] is! BlueBox ||
     row.children[3] is! Spacer ||
     row.children[4] is! BlueBox) {
    _result(false, ['Not quite. Row should contain five children in this order: BlueBox, Spacer, BlueBox, Spacer, BlueBox.']);
    return;
  }
  
    final spacer = row.children[3] as Spacer;
  
    if (spacer.flex != 1) {
    _result(false, ['The Spacer class should have a flex equal to 1.']);
    return;
  }
  
  _result(true, ['Both Spacer widgets create equal amounts of space between all three BlueBox widgets.']);
}
{$ end test.dart $}

テキストウィジェット

Textウィジェットにはテキストが表示され、設定可能 さまざまなフォント、サイズ、色に対応します。

例: テキストの配置

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.center,
      textBaseline: TextBaseline.alphabetic,
      children: const [
        Text(
          'Hey!',
          style: TextStyle(
            fontSize: 30,
            fontFamily: 'Futura',
            color: Colors.blue,
          ),
        ),
        Text(
          'Hey!',
          style: TextStyle(
            fontSize: 50,
            fontFamily: 'Futura',
            color: Colors.green,
          ),
        ),
        Text(
          'Hey!',
          style: TextStyle(
            fontSize: 40,
            fontFamily: 'Futura',
            color: Colors.red,
          ),
        ),
      ],
    );
  }
}
{$ end main.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        color: const Color(0xffeeeeee),
        child: Center(
          child: Container(
            color: const Color(0xffcccccc),
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  final rows = controller.widgetList(find.byType(Row));

  if (rows.isEmpty) {
    _result(false, ['Couldn\'t find a Row!']);
    return;
  }

  if (rows.length > 1) {
    _result(false, ['Found ${rows.length} Rows, rather than just one.']);
    return;
  }

  final row = rows.first as Row;

  if (row.mainAxisSize != MainAxisSize.max) {
    _result(false, ['It\'s best to leave the mainAxisSize set to MainAxisSize.max, so there\'s space for the alignments to take effect.']);
    return;
  }
  
  if (row.children.length != 3 || row.children.any((w) => w is! Text)) {
    _result(false, ['The Row should have three children, all Text widgets.']);
    return;
  }

  if (row.textBaseline == null) {
    _result(false, ['To use CrossAxisAlignment.baseline, you need to set the Row\'s textBaseline property.']);
    return;
  } 
  
  if (row.crossAxisAlignment != CrossAxisAlignment.baseline) {
    _result(false, ['The Text widgets are positioned at the middle of the cross axis. Change CrossAxisAlignment.center to CrossAxisAlignment.baseline.']);
		return;
  }  

  _result(true, ['The Text widgets are now aligned by their character baselines.']);
  
}
{$ end test.dart $}

アイコンウィジェット

Iconウィジェットにはグラフィックシンボルが表示されます UI の側面を表します。 Flutter には、次のアイコン パッケージがプリロードされています。材料とクパチーノアプリケーション。

例: アイコンの作成

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.center,
      textBaseline: TextBaseline.alphabetic,
      children: const [
        Icon(
          Icons.widgets,
          size: 50,
          color: Colors.blue,
        ),
        Icon(
          Icons.widgets,
          size: 50,
          color: Colors.red,
        ),
      ],
    );
  }
}
{$ end main.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        color: const Color(0xffeeeeee),
        child: Center(
          child: Container(
            color: const Color(0xffcccccc),
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  final rows = controller.widgetList(find.byType(Row));

  if (rows.isEmpty) {
    _result(false, ['Couldn\'t find a Row!']);
    return;
  }

  if (rows.length > 1) {
    _result(false, ['Found ${rows.length} Rows, rather than just one.']);
    return;
  }

  final row = rows.first as Row;

  if (row.mainAxisSize != MainAxisSize.max) {
    _result(false, ['It\'s best to leave the mainAxisSize set to MainAxisSize.max, so there\'s space for the alignments to       take effect.']);
    return;
  }
  
    if (row.children.length != 3 || row.children.any((w) => w is! Icon)) {
    _result(false, ['Row should have three children, all Icon widgets.']);
    return;
  }

    final icon = row.children[2] as Icon;
  
  if (icon.color != Colors.amber) {
    _result(false, ['Add a third Icon. Give the Icon a size of 50 and a color of Colors.amber.']);
    return;
  }
  
  _result(true, ['The code displays three Icons in blue, red, and amber.']);
  
}
{$ end test.dart $}

画像ウィジェット

Imageウィジェットには画像が表示されます。 URL を使用して画像を参照することも、 または、アプリ パッケージ内に画像を含めることもできます。 DartPadは画像をパッケージ化できないため、 次の例では、ネットワークからの画像を使用します。

例:画像を表示する

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Image.network('[Place an image link here!]'),
      ],
    );
  }
}
{$ end main.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        color: const Color(0xffeeeeee),
        child: Center(
          child: Container(
            color: const Color(0xffcccccc),
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  final rows = controller.widgetList(find.byType(Row));

  if (rows.isEmpty) {
    _result(false, ['Couldn\'t find a Row!']);
    return;
  }

  if (rows.length > 1) {
    _result(false, ['Found ${rows.length} Rows, rather than just one.']);
    return;
  }

  final row = rows.first as Row;

  if (row.mainAxisSize != MainAxisSize.max) {
    _result(false, ['It\'s best to leave the mainAxisSize set to MainAxisSize.max, so there\'s space for the alignments to take effect.']);
    return;
  }
 
}
{$ end test.dart $}

すべてを一緒に入れて

このコードラボはもうすぐ終わりです。 に関する知識をテストしたい場合は、 学んだテクニックを応用してみませんか Flutter UI を構築するためのこれらのスキル 名刺を表示します!

Completed business card

Flutter のレイアウトをいくつかの部分に分解します。 これは、現実世界で Flutter UI を作成する方法です。

パート1、 を実装しますColumn名前とタイトルが含まれています。 次に、ColumnRowアイコンが含まれている、 これは名前とタイトルの左側に配置されます。

Completed business card

パート2をラップします。RowColumn、 したがって、コードにはColumn以内Row以内Column。 次に、最も外側を微調整しますColumnのレイアウト、 だから見た目もいいです。 最後に連絡先情報を追加します 一番外側までColumnの子供のリスト、 したがって、名前、タイトル、アイコンの下に表示されます。

Completed business card

パート 3、構築が完了します さらに 4 つのアイコンを追加して名刺を表示します。 これらは連絡先情報の下にあります。

Completed business card

パート1

演習: 名前とタイトルを作成する

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    TODO('Begin implementing the Column here.');
  }
}
{$ end main.dart $}
{$ begin solution.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          'Flutter McFlutter', 
          style: Theme.of(context).textTheme.headlineSmall,
        ),
        const Text('Experienced App Developer'),
      ],
    );
  }
}
{$ end solution.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        scaffoldBackgroundColor: const Color(0xffeeeeee),
        textTheme: const TextTheme(
          bodyMedium: TextStyle(
            fontSize: 16,
          ),
        ),
      ),
      home: Scaffold(
        body: Padding(
          padding: const EdgeInsets.all(16),
          child: Center(
            child: Container(
              decoration: BoxDecoration(
                color: const Color(0xffffffff),
                border: Border.all(),
                boxShadow: const [
                  BoxShadow(
                    blurRadius: 10,
                    color: Color(0x80000000),
                  ),
                ],
              ),
              padding: const EdgeInsets.all(8),
              child: MyWidget(),
            ),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  // Check MyWidget starts with one Column

  final myWidgetElement = controller.element(find.byType(MyWidget));

  final myWidgetChildElements = <Element>[];
  myWidgetElement.visitChildElements((e) => myWidgetChildElements.add(e));

  if (myWidgetChildElements.length != 1 ||
      myWidgetChildElements[0].widget is! Column) {
    _result(false, ['The root widget in MyWidget\'s build method should be a Column.']);
    return;
  }

  // Check Column has correct properties

  final innerColumnElement = myWidgetChildElements[0];
  final innerColumnWidget = innerColumnElement.widget as Column;

  if (innerColumnWidget.crossAxisAlignment != CrossAxisAlignment.start) {
    _result(false, ['The Column that contains the name and title should use CrossAxisAlignment.start as its CrossAxisAlignment value.']);
    return;
  }

  if (innerColumnWidget.mainAxisSize != MainAxisSize.min) {
    _result(false, ['The Column that contains the name and title should use MainAxisSize.min as its MainAxisSize value.']);
    return;
  }

  // Check inner Column has two Text children

  if (innerColumnWidget.children.any((w) => w is! Text)) {
    _result(false, ['The Column that contains the name and title should have two children, both Text widgets.']);
    return;
  }

  // Check first Text has headline style

  final nameText = innerColumnWidget.children[0] as Text;

  if (nameText.style?.fontSize != 24) {
    _result(false, ['The Text widget for the name should use the "headlineSmall" textStyle.']);
    return;
  }

  _result(true);
}
{$ end test.dart $}

演習: 列を行内で折り返す

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          'Flutter McFlutter',
          style: Theme.of(context).textTheme.headlineSmall,
        ),
        const Text('Experienced App Developer'),
      ],
    );
  }
}
{$ end main.dart $}
{$ begin solution.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        const Padding(
          padding: EdgeInsets.all(8),
          child: Icon(Icons.account_circle, size: 50),
        ),
        Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Flutter McFlutter',
              style: Theme.of(context).textTheme.headlineSmall,
            ),
            const Text('Experienced App Developer'),
          ],
        ),
      ],
    );
  }
}
{$ end solution.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        scaffoldBackgroundColor: const Color(0xffeeeeee),
        textTheme: const TextTheme(
          bodyMedium: TextStyle(
            fontSize: 16,
          ),
        ),
      ),
      home: Scaffold(
        body: Padding(
          padding: const EdgeInsets.all(16),
          child: Center(
            child: Container(
              decoration: BoxDecoration(
                color: const Color(0xffffffff),
                border: Border.all(),
                boxShadow: const [
                  BoxShadow(
                    blurRadius: 10,
                    color: Color(0x80000000),
                  ),
                ],
              ),
              padding: const EdgeInsets.all(8.0),
              child: MyWidget(),
            ),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  // Check MyWidget starts with one Column

  final myWidgetElement = controller.element(find.byType(MyWidget));

  final myWidgetChildElements = <Element>[];
  myWidgetElement.visitChildElements((e) => myWidgetChildElements.add(e));

  if (myWidgetChildElements.length != 1 ||
      myWidgetChildElements[0].widget is! Row) {
    _result(false, ['The root widget in MyWidget\'s build method should be a Column.']);
    return;
  }

  // Check first Row has two children: Padding and Column

  final firstRowElement = myWidgetChildElements[0];

  final firstRowChildElements = <Element>[];
  firstRowElement.visitChildElements((e) => firstRowChildElements.add(e));

  if (firstRowChildElements.length != 2 ||
      firstRowChildElements[0].widget is! Padding ||
      firstRowChildElements[1].widget is! Column) {
    _result(false, ['The first Row should have two children: first a Padding, and then a Column.']);
    return;
  }

  // Check Padding has correct padding

  final paddingElement = firstRowChildElements[0];

  if ((paddingElement.widget as Padding).padding != const EdgeInsets.all(8)) {
    _result(false, ['The Padding widget in the first Row should have a padding of 8.']);
    return;
  }

  // Check Padding has an Icon as its child

  final paddingChildren = <Element>[];
  paddingElement.visitChildElements((e) => paddingChildren.add(e));

  if (paddingChildren.length != 1 || paddingChildren[0].widget is! Icon) {
    _result(false, ['The Padding widget in the first Row should have an Icon as its child.']);
    return;
  }

  // Check icon has a size of 50

  if ((paddingChildren[0].widget as Icon).size != 50) {
    _result(false, ['The Icon in the top-left corner should have a size of 50.']);
    return;
  }

  // Check inner Column has correct properties

  final innerColumnElement = firstRowChildElements[1];
  final innerColumnWidget = innerColumnElement.widget as Column;

  if (innerColumnWidget.crossAxisAlignment != CrossAxisAlignment.start) {
    _result(false, ['The Column for the name and title should use CrossAxisAlignment.start as its crosAxisAlignment.']);
    return;
  }

  if (innerColumnWidget.mainAxisSize != MainAxisSize.min) {
    _result(false, ['The Column for the name and title should use MainAxisSize.min as its mainAxisSize.']);
    return;
  }

  // Check inner Column has two Text children

  if (innerColumnWidget.children.any((w) => w is! Text)) {
    _result(false, ['The Column for the name and title should have two children, both Text widgets.']);
    return;
  }

  // Check first Text has headline style

  final nameText = innerColumnWidget.children[0] as Text;

  if (nameText.style?.fontSize != 24) {
    _result(false, ['The Text widget for the name should use the "headlineSmall" textStyle.']);
    return;
  }

  _result(true);
}
{$ end test.dart $}

パート2

演習: レイアウトを調整する

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        const Padding(
          padding: EdgeInsets.all(8.0),
          child: Icon(Icons.account_circle, size: 50),
        ),
        Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Flutter McFlutter',
              style: Theme.of(context).textTheme.headlineSmall,
            ),
            const Text('Experienced App Developer'),
          ],
        ),
      ],
    );
  }
}
{$ end main.dart $}
{$ begin solution.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Row(
          children: [
            const Padding(
              padding: EdgeInsets.all(8.0),
              child: Icon(Icons.account_circle, size: 50),
            ),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  'Flutter McFlutter',
                  style: Theme.of(context).textTheme.headlineSmall,
                ),
                const Text('Experienced App Developer'),
              ],
            ),
          ],
        ),
        const SizedBox(height: 8),
        Row(),
        const SizedBox(height: 16),
        Row(),
      ],
    );
  }
}
{$ end solution.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        scaffoldBackgroundColor: const Color(0xffeeeeee),
        textTheme: const TextTheme(
          bodyMedium: TextStyle(
            fontSize: 16,
          ),
        ),
      ),
      home: Scaffold(
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Center(
            child: Container(
              decoration: BoxDecoration(
                color: const Color(0xffffffff),
                border: Border.all(),
                boxShadow: const [
                  BoxShadow(
                    blurRadius: 10,
                    color: Color(0x80000000),
                  ),
                ],
              ),
              padding: const EdgeInsets.all(8.0),
              child: MyWidget(),
            ),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  // Check MyWidget starts with one Column

  final myWidgetElement = controller.element(find.byType(MyWidget));

  final myWidgetChildElements = <Element>[];
  myWidgetElement.visitChildElements((e) => myWidgetChildElements.add(e));

  if (myWidgetChildElements.length != 1 ||
      myWidgetChildElements[0].widget is! Column) {
    _result(false, ['The root widget in MyWidget\'s build method should be a Column.']);
    return;
  }

  // Check outermost Column has 5 correct children.

  final outerColumnElement = myWidgetChildElements[0];
  final outerColumnChildWidgets =
      (outerColumnElement.widget as Column).children;
  final outerColumnChildElements = <Element>[];
  outerColumnElement.visitChildElements((e) => outerColumnChildElements.add(e));

  if (outerColumnChildWidgets.length != 5 ||
      outerColumnChildWidgets[0] is! Row ||
      outerColumnChildWidgets[1] is! SizedBox ||
      outerColumnChildWidgets[2] is! Row ||
      outerColumnChildWidgets[3] is! SizedBox ||
      outerColumnChildWidgets[4] is! Row) {
    _result(false, ['The children of the outermost Column should be [Row, SizedBox, Row, SizedBox, Row] in that order.']);
    return;
  }

  // Check outermost Column's properties

  if ((outerColumnElement.widget as Column).mainAxisSize != MainAxisSize.min) {
    _result(false, ['The outermost Column should use MainAxisSize.min for its mainAxisSize.']);
    return;
  }

  if ((outerColumnElement.widget as Column).crossAxisAlignment !=
      CrossAxisAlignment.stretch) {
    _result(false, ['The outermost Column should use CrossAxisAlignment.stretch for its crossAxisAlignment.']);
    return;
  }

  // Check first Row has two children: Padding and Column

  final firstRowElement = outerColumnChildElements
      .firstWhere((e) => e.widget == outerColumnChildWidgets[0]);

  final firstRowChildElements = <Element>[];
  firstRowElement.visitChildElements((e) => firstRowChildElements.add(e));

  if (firstRowChildElements.length != 2 ||
      firstRowChildElements[0].widget is! Padding ||
      firstRowChildElements[1].widget is! Column) {
    _result(false, ['The first Row should have two children: first a Padding, and then a Column.']);
    return;
  }

  // Check Padding has correct padding

  final paddingElement = firstRowChildElements[0];

  if ((paddingElement.widget as Padding).padding != const EdgeInsets.all(8)) {
    _result(false, ['The Padding widget in the first Row should have a padding of 8.']);
    return;
  }

  // Check Padding has an Icon as its child

  final paddingChildren = <Element>[];
  paddingElement.visitChildElements((e) => paddingChildren.add(e));

  if (paddingChildren.length != 1 || paddingChildren[0].widget is! Icon) {
    _result(false, ['The Padding widget in the first Row should have an Icon as its child.']);
    return;
  }

  // Check icon has a size of 50

  if ((paddingChildren[0].widget as Icon).size != 50) {
    _result(false, ['The Icon in the top-left corner should have a size of 50.']);
    return;
  }

  // Check inner Column has correct properties

  final innerColumnElement = firstRowChildElements[1];
  final innerColumnWidget = innerColumnElement.widget as Column;

  if (innerColumnWidget.crossAxisAlignment != CrossAxisAlignment.start) {
    _result(false, ['The Column for the name and title should use CrossAxisAlignment.start as its crosAxisAlignment.']);
    return;
  }

  if (innerColumnWidget.mainAxisSize != MainAxisSize.min) {
    _result(false, ['The Column for the name and title should use MainAxisSize.min as its mainAxisSize.']);
    return;
  }

  // Check inner Column has two Text children

  if (innerColumnWidget.children.any((w) => w is! Text)) {
    _result(false, ['The Column for the name and title should have two children, both Text widgets.']);
    return;
  }

  // Check first Text has headline style

  final nameText = innerColumnWidget.children[0] as Text;

  if (nameText.style?.fontSize != 24) {
    _result(false, ['The Text widget for the name should use the "headlineSmall" textStyle.']);
    return;
  }

  // Check first SizedBox has correct properties

  final firstSizedBoxElement = outerColumnChildElements
      .firstWhere((e) => e.widget == outerColumnChildWidgets[1]);

  if ((firstSizedBoxElement.widget as SizedBox).height != 8) {
    _result(false, ['The SizedBox before the first empty Row should have a height of 8.']);
    return;
  }

  // Check second SizedBox has correct properties

  final secondSizedBoxElement = outerColumnChildElements
      .firstWhere((e) => e.widget == outerColumnChildWidgets[3]);

  if ((secondSizedBoxElement.widget as SizedBox).height != 16) {
    _result(false, ['The SizedBox between the first and second empty Rows should have a height of 16.']);
    return;
  }

  _result(true);
}
{$ end test.dart $}

演習: 連絡先情報を入力してください

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Row(
          children: [
            const Padding(
              padding: EdgeInsets.all(8.0),
              child: Icon(Icons.account_circle, size: 50),
            ),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  'Flutter McFlutter',
                  style: Theme.of(context).textTheme.headlineSmall,
                ),
                const Text('Experienced App Developer'),
              ],
            ),
          ],
        ),
        const SizedBox(height: 8),
        Row(
          children: const [],
        ),
        const SizedBox(height: 16),
        Row(
          children: const [],
        ),
      ],
    );
  }
}
{$ end main.dart $}
{$ begin solution.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Row(
          children: [
            const Padding(
              padding: EdgeInsets.all(8.0),
              child: Icon(Icons.account_circle, size: 50),
            ),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  'Flutter McFlutter',
                  style: Theme.of(context).textTheme.headlineSmall,
                ),
                const Text('Experienced App Developer'),
              ],
            ),
          ],
        ),
        const SizedBox(height: 8),
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: const [
            Text(
              '123 Main Street',
            ),
            Text(
              '(415) 555-0198',
            ),
          ],
        ),
        const SizedBox(height: 16),
        Row(
          children: const [],
        ),
      ],
    );
  }
}
{$ end solution.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        scaffoldBackgroundColor: const Color(0xffeeeeee),
        textTheme: const TextTheme(
          bodyMedium: TextStyle(
            fontSize: 16,
          ),
        ),
      ),
      home: Scaffold(
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Center(
            child: Container(
              decoration: BoxDecoration(
                color: const Color(0xffffffff),
                border: Border.all(),
                boxShadow: const [
                  BoxShadow(
                    blurRadius: 10,
                    color: Color(0x80000000),
                  ),
                ],
              ),
              padding: const EdgeInsets.all(8.0),
              child: MyWidget(),
            ),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  // Check MyWidget starts with one Column

  final myWidgetElement = controller.element(find.byType(MyWidget));

  final myWidgetChildElements = <Element>[];
  myWidgetElement.visitChildElements((e) => myWidgetChildElements.add(e));

  if (myWidgetChildElements.length != 1 ||
      myWidgetChildElements[0].widget is! Column) {
    _result(false, ['The root widget in MyWidget\'s build method should be a Column.']);
    return;
  }

  // Check outermost Column has 5 correct children.

  final outerColumnElement = myWidgetChildElements[0];
  final outerColumnChildWidgets =
      (outerColumnElement.widget as Column).children;
  final outerColumnChildElements = <Element>[];
  outerColumnElement.visitChildElements((e) => outerColumnChildElements.add(e));

  if (outerColumnChildWidgets.length != 5 ||
      outerColumnChildWidgets[0] is! Row ||
      outerColumnChildWidgets[1] is! SizedBox ||
      outerColumnChildWidgets[2] is! Row ||
      outerColumnChildWidgets[3] is! SizedBox ||
      outerColumnChildWidgets[4] is! Row) {
    _result(false, ['The children of the outermost Column should be [Row, SizedBox, Row, SizedBox, Row] in that order.']);
    return;
  }

  // Check outermost Column's properties

  if ((outerColumnElement.widget as Column).mainAxisSize != MainAxisSize.min) {
    _result(false, ['The outermost Column should use MainAxisSize.min for its mainAxisSize.']);
    return;
  }

  if ((outerColumnElement.widget as Column).crossAxisAlignment !=
      CrossAxisAlignment.stretch) {
    _result(false, ['The outermost Column should use CrossAxisAlignment.stretch for its crossAxisAlignment.']);
    return;
  }

  // Check first Row has two children: Padding and Column

  final firstRowElement = outerColumnChildElements
      .firstWhere((e) => e.widget == outerColumnChildWidgets[0]);

  final firstRowChildElements = <Element>[];
  firstRowElement.visitChildElements((e) => firstRowChildElements.add(e));

  if (firstRowChildElements.length != 2 ||
      firstRowChildElements[0].widget is! Padding ||
      firstRowChildElements[1].widget is! Column) {
    _result(false, ['The first Row should have two children: first a Padding, and then a Column.']);
    return;
  }

  // Check Padding has correct padding

  final paddingElement = firstRowChildElements[0];

  if ((paddingElement.widget as Padding).padding != const EdgeInsets.all(8)) {
    _result(false, ['The Padding widget in the first Row should have a padding of 8.']);
    return;
  }

  // Check Padding has an Icon as its child

  final paddingChildren = <Element>[];
  paddingElement.visitChildElements((e) => paddingChildren.add(e));

  if (paddingChildren.length != 1 || paddingChildren[0].widget is! Icon) {
    _result(false, ['The Padding widget in the first Row should have an Icon as its child.']);
    return;
  }

  // Check icon has a size of 50

  if ((paddingChildren[0].widget as Icon).size != 50) {
    _result(false, ['The Icon in the top-left corner should have a size of 50.']);
    return;
  }

  // Check inner Column has correct properties

  final innerColumnElement = firstRowChildElements[1];
  final innerColumnWidget = innerColumnElement.widget as Column;

  if (innerColumnWidget.crossAxisAlignment != CrossAxisAlignment.start) {
    _result(false, ['The Column for the name and title should use CrossAxisAlignment.start as its crosAxisAlignment.']);
    return;
  }

  if (innerColumnWidget.mainAxisSize != MainAxisSize.min) {
    _result(false, ['The Column for the name and title should use MainAxisSize.min as its mainAxisSize.']);
    return;
  }

  // Check inner Column has two Text children

  if (innerColumnWidget.children.any((w) => w is! Text)) {
    _result(false, ['The Column for the name and title should have two children, both Text widgets.']);
    return;
  }

  // Check first Text has headline style

  final nameText = innerColumnWidget.children[0] as Text;

  if (nameText.style?.fontSize != 24) {
    _result(false, ['The Text widget for the name should use the "headlineSmall" textStyle.']);
    return;
  }

  // Check first SizedBox has correct properties

  final firstSizedBoxElement = outerColumnChildElements
      .firstWhere((e) => e.widget == outerColumnChildWidgets[1]);

  if ((firstSizedBoxElement.widget as SizedBox).height != 8) {
    _result(false, ['The SizedBox before the first empty Row widget should have a height of 8.']);
    return;
  }

  // Check second Row has two Text children

  final secondRowElement = outerColumnChildElements
      .firstWhere((e) => e.widget == outerColumnChildWidgets[2]);

  final secondRowChildElements = <Element>[];
  secondRowElement.visitChildElements((e) => secondRowChildElements.add(e));

  if (secondRowChildElements.length != 2 ||
      secondRowChildElements.any((e) => e.widget is! Text)) {
    _result(false, ['The first empty Row widget should have two children, both Text widgets.']);
    return;
  }

  // Check second Row has correct properties

  if ((secondRowElement.widget as Row).mainAxisAlignment !=
      MainAxisAlignment.spaceBetween) {
    _result(false, ['The first empty Row widget should use MainAxisAlignment.spaceBetween as its MainAxisAlignment value.']);
    return;
  }

  // Check second SizedBox has correct properties

  final secondSizedBoxElement = outerColumnChildElements
      .firstWhere((e) => e.widget == outerColumnChildWidgets[3]);

  if ((secondSizedBoxElement.widget as SizedBox).height != 16) {
    _result(false, ['The SizedBox between the first and second empty Row widgets should have a height of 16.']);
    return;
  }

  _result(true);
}
{$ end test.dart $}

パート 3

演習: 4 つのアイコンを追加する

{$ begin main.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Row(
          children: [
            const Padding(
              padding: EdgeInsets.all(8.0),
              child: Icon(Icons.account_circle, size: 50),
            ),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  'Flutter McFlutter',
                  style: Theme.of(context).textTheme.headlineSmall,
                ),
                const Text('Experienced App Developer'),
              ],
            ),
          ],
        ),
        const SizedBox(height: 8),
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: const [
            Text('123 Main Street'),
            Text('415-555-0198'),
          ],
        ),
        const SizedBox(height: 16),
        Row(
          children: const [],
        ),
      ],
    );
  }
}
{$ end main.dart $}
{$ begin solution.dart $}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Row(
          children: [
            const Padding(
              padding: EdgeInsets.all(8.0),
              child: Icon(Icons.account_circle, size: 50),
            ),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  'Flutter McFlutter',
                  style: Theme.of(context).textTheme.headlineSmall,
                ),
                const Text('Experienced App Developer'),
              ],
            ),
          ],
        ),
        const SizedBox(height: 8),
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: const [
            Text(
              '123 Main Street',
            ),
            Text(
              '(415) 555-0198',
            ),
          ],
        ),
        const SizedBox(height: 16),
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: const [
            Icon(Icons.accessibility),
            Icon(Icons.timer),
            Icon(Icons.phone_android),
            Icon(Icons.phone_iphone),
          ],
        ),
      ],
    );
  }
}
{$ end solution.dart $}
{$ begin test.dart $}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        scaffoldBackgroundColor: const Color(0xffeeeeee),
        textTheme: const TextTheme(
          bodyMedium: TextStyle(
            fontSize: 16,
          ),
        ),
      ),
      home: Scaffold(
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Center(
            child: Container(
              decoration: BoxDecoration(
                color: const Color(0xffffffff),
                border: Border.all(),
                boxShadow: const [
                  BoxShadow(
                    blurRadius: 10,
                    color: Color(0x80000000),
                  ),
                ],
              ),
              padding: const EdgeInsets.all(8.0),
              child: MyWidget(),
            ),
          ),
        ),
      ),
    );
  }
}

Future<void> main() async {
  final completer = Completer<void>();
  
  runApp(MyApp());

  WidgetsFlutterBinding.ensureInitialized()
      .addPostFrameCallback((timestamp) async {
    completer.complete();
  });
  
  await completer.future;

  final controller = LiveWidgetController(WidgetsBinding.instance);

  // Check MyWidget starts with one Column

  final myWidgetElement = controller.element(find.byType(MyWidget));

  final myWidgetChildElements = <Element>[];
  myWidgetElement.visitChildElements((e) => myWidgetChildElements.add(e));

  if (myWidgetChildElements.length != 1 ||
      myWidgetChildElements[0].widget is! Column) {
    _result(false, ['The root widget in MyWidget\'s build method should be a Column.']);
    return;
  }

  // Check outermost Column has 5 correct children.

  final outerColumnElement = myWidgetChildElements[0];
  final outerColumnChildWidgets =
      (outerColumnElement.widget as Column).children;
  final outerColumnChildElements = <Element>[];
  outerColumnElement.visitChildElements((e) => outerColumnChildElements.add(e));

  if (outerColumnChildWidgets.length != 5 ||
      outerColumnChildWidgets[0] is! Row ||
      outerColumnChildWidgets[1] is! SizedBox ||
      outerColumnChildWidgets[2] is! Row ||
      outerColumnChildWidgets[3] is! SizedBox ||
      outerColumnChildWidgets[4] is! Row) {
    _result(false, ['The children of the outermost Column should be [Row, SizedBox, Row, SizedBox, Row] in that order.']);
    return;
  }

  // Check outermost Column's properties

  if ((outerColumnElement.widget as Column).mainAxisSize != MainAxisSize.min) {
    _result(false, ['The outermost Column should use MainAxisSize.min for its mainAxisSize.']);
    return;
  }

  if ((outerColumnElement.widget as Column).crossAxisAlignment !=
      CrossAxisAlignment.stretch) {
    _result(false, ['The outermost Column should use CrossAxisAlignment.stretch for its crossAxisAlignment.']);
    return;
  }

  // Check first Row has two children: Padding and Column

  final firstRowElement = outerColumnChildElements
      .firstWhere((e) => e.widget == outerColumnChildWidgets[0]);

  final firstRowChildElements = <Element>[];
  firstRowElement.visitChildElements((e) => firstRowChildElements.add(e));

  if (firstRowChildElements.length != 2 ||
      firstRowChildElements[0].widget is! Padding ||
      firstRowChildElements[1].widget is! Column) {
    _result(false, ['The first Row should have two children: first a Padding, and then a Column.']);
    return;
  }

  // Check Padding has correct padding

  final paddingElement = firstRowChildElements[0];

  if ((paddingElement.widget as Padding).padding != const EdgeInsets.all(8)) {
    _result(false, ['The Padding widget in the first Row should have a padding of 8.']);
    return;
  }

  // Check Padding has an Icon as its child

  final paddingChildren = <Element>[];
  paddingElement.visitChildElements((e) => paddingChildren.add(e));

  if (paddingChildren.length != 1 || paddingChildren[0].widget is! Icon) {
    _result(false, ['The Padding widget in the first Row should have an Icon as its child.']);
    return;
  }

  // Check icon has a size of 50

  if ((paddingChildren[0].widget as Icon).size != 50) {
    _result(false, ['The Icon in the top-left corner should have a size of 50.']);
    return;
  }

  // Check inner Column has correct properties

  final innerColumnElement = firstRowChildElements[1];
  final innerColumnWidget = innerColumnElement.widget as Column;

  if (innerColumnWidget.crossAxisAlignment != CrossAxisAlignment.start) {
    _result(false, ['The Column for the name and title should use CrossAxisAlignment.start as its crosAxisAlignment.']);
    return;
  }

  // Check inner Column has two Text children

  if (innerColumnWidget.children.any((w) => w is! Text)) {
    _result(false, ['The Column for the name and title should have two children, both Text widgets.']);
    return;
  }

  if (innerColumnWidget.mainAxisSize != MainAxisSize.min) {
    _result(false, ['The Column for the name and title should use MainAxisSize.min as its mainAxisSize.']);
    return;
  }

  // Check first Text has headline style

  final nameText = innerColumnWidget.children[0] as Text;

  if (nameText.style?.fontSize != 24) {
    _result(false, ['The Text widget for the name should use the "headlineSmall" textStyle.']);
    return;
  }

  // Check first SizedBox has correct properties

  final firstSizedBoxElement = outerColumnChildElements
      .firstWhere((e) => e.widget == outerColumnChildWidgets[1]);

  if ((firstSizedBoxElement.widget as SizedBox).height != 8) {
    _result(false, ['The SizedBox before the first empty Row widget should have a height of 8.']);
    return;
  }

  // Check second Row has two Text children

  final secondRowElement = outerColumnChildElements
      .firstWhere((e) => e.widget == outerColumnChildWidgets[2]);

  final secondRowChildElements = <Element>[];
  secondRowElement.visitChildElements((e) => secondRowChildElements.add(e));

  if (secondRowChildElements.length != 2 ||
      secondRowChildElements.any((e) => e.widget is! Text)) {
    _result(false, ['The first Row widget should have two children, both Text widgets.']);
    return;
  }

  // Check second Row has correct properties

  if ((secondRowElement.widget as Row).mainAxisAlignment !=
      MainAxisAlignment.spaceBetween) {
    _result(false, ['The first Row widget should use MainAxisAlignment.spaceBetween as its mainAxisAlignment.']);
    return;
  }

  // Check second SizedBox has correct properties

  final secondSizedBoxElement = outerColumnChildElements
      .firstWhere((e) => e.widget == outerColumnChildWidgets[3]);

  if ((secondSizedBoxElement.widget as SizedBox).height != 16) {
    _result(false, ['The SizedBox between the first and second Row widgets should have a height of 16.']);
    return;
  }

  // Check second empty Row has four Icon children

  final thirdRowElement = outerColumnChildElements
      .firstWhere((e) => e.widget == outerColumnChildWidgets[4]);

  final thirdRowChildElements = <Element>[];
  thirdRowElement.visitChildElements((e) => thirdRowChildElements.add(e));

  if (thirdRowChildElements.length != 4 ||
      thirdRowChildElements.any((e) => e.widget is! Icon)) {
    _result(false, ['The second empty Row widget should have four children, all Icon widgets.']);
    return;
  }

  // Check second empty Row has correct properties

  if ((thirdRowElement.widget as Row).mainAxisAlignment !=
      MainAxisAlignment.spaceAround) {
    _result(false, ['The second empty Row widget should use MainAxisAlignment.spaceAround as its MainAxisAligment value.']);
    return;
  }

  _result(true);
}
{$ end test.dart $}

次は何ですか?

おめでとうございます。このコードラボは完了しました。 Flutter についてさらに詳しく知りたい場合は、 検討する価値のあるリソースについて、いくつかの提案を示します。

  • Flutter のレイアウトの詳細については、こちらをご覧ください。 を訪問する建物のレイアウトページ。
  • をチェックしてくださいサンプルアプリ。
  • 訪問FlutterのYouTubeチャンネル、 さまざまなビデオを視聴できる場所 個々のウィジェットに焦点を当てたビデオ アプリを構築する開発者のビデオへ。

Flutter は次からダウンロードできます。インストールページ。